package com.mlming.simpledb.backend.tm;

import com.mlming.simpledb.backend.utils.Panic;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;

import com.mlming.simpledb.common.Error;
import com.sun.beans.editors.ByteEditor;

public interface TransactionManager {
    long begin(); // 开启一个事务,并返回xid
    void commit(long xid); // 指定提交一个事务
    void abort(long xid); // 指定回滚一个事务
    boolean isActive(long xid); // 查询一个事务的状态是否是正在进行的状态
    boolean isCommitted(long xid); // 查询一个事务的状态是否是已提交
    boolean isAborted(long xid); // 查询一个事务的状态是否是已回滚
    void close(); // 关闭TM

    /**
     * 用于创建XID文件 且 创建TM,
     * @param path 指定XID文件创建路径
     * @return TM
     */
    public static TransactionManagerImpl create(String path) {
        // 1) 根据路径创建XID文件:
        File XIDFile = new File(path + TransactionManagerImpl.XID_SUFFIX);
        try {
            if (!XIDFile.createNewFile()) {
                Panic.panic(Error.FileExistsException);
            }
        } catch (IOException e) {
            Panic.panic(e);
        }
        if(!XIDFile.canRead() || !XIDFile.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }
        // 2) 构造TransactionManagerImpl所需参数:
        RandomAccessFile raf = null;
        FileChannel fc = null;
        try {
            raf = new RandomAccessFile(XIDFile,"rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }
        // 3) 通过fc往XID文件写入空文件头:
        ByteBuffer buf = ByteBuffer.wrap(new byte[TransactionManagerImpl.XID_HEADER_LENGTH]);
        try {
            fc.position(0); // 定位到文件的开始
            fc.write(buf); // 写入XID文件
        } catch (IOException e) {
            Panic.panic(e);
        }
        // 4) 调用构造函数创建TransactionManagerImpl
        return new TransactionManagerImpl(raf,fc);
    }

    /**
     * 通过path指定已存在的XID文件, 来创建TM
     * @param path 已经存在的XID文件的路径
     * @return TM
     */
    public static TransactionManagerImpl open(String path) {
        // 1) 检测XID文件的合法性
        File XIDFile = new File(path + TransactionManagerImpl.XID_SUFFIX);
        if(!XIDFile.exists()) {
            Panic.panic(Error.FileNotExistsException);
        }
        if(!XIDFile.canRead() || !XIDFile.canWrite()) {
            Panic.panic(Error.FileCannotRWException);
        }
        // 2) 构造TM构造函数的参数
        RandomAccessFile raf = null;
        FileChannel fc = null;
        try {
            raf = new RandomAccessFile(XIDFile, "rw");
            fc = raf.getChannel();
        } catch (FileNotFoundException e) {
            Panic.panic(e);
        }
        // 3) 构造TM
        return new TransactionManagerImpl(raf, fc);
    }
}
